#include "common.h"
#include "ucos/includes.h"

#include "lwip/debug.h"
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "lwip/tcpip.h"
#include "lwip/api.h"
#include "netif/arp.h"
#include "netif/loopif.h"
#include "netif/ne2kif.h"
#include "arch/sys_arch.h"

extern void OSISR(void);

#define N_TASK 2
#define STK_SIZE 1024
OS_STK stacks[N_TASK][STK_SIZE];
OS_EVENT* sem;

void task1(void* p);
void task2(void* p);
void install_irqhandler(void * isr);
void tcpip_init_done(void *arg);
void tcpecho_init(void);
void tcpecho_thread(void *arg);

extern struct netif *rtl8019if_netif;                          
struct RTL8019if *rtlif;

int c_start(void) {
	//char c1;

    (void)install_irqhandler(OSISR);

	//uart_sendstring("in c_start\n");

	OSInit();

	sem = OSSemCreate(0);
	OSTaskCreate(task1,NULL,&stacks[0][STK_SIZE],0);
	OSTaskCreate(task2,NULL,&stacks[1][STK_SIZE],1);
	
	OSStart();

	/*
	uart_sendstring("in c_start while\n");
	while(1) {
		//uart_sendbyte(0xa);
		//uart_sendbyte(0xd);
		#if 1
		c1 = uart_getch();
		uart_sendbyte(c1);
		#else
		;
		#endif
	}

	*/

	return 0;
}

void task1(void* p) {

    struct ip_addr ipaddr, netmask, gw;
    struct netconn* conn;
    sys_sem_t sem;
	int c;

	print("in task1\n");

	board_init();

#if 1
    
#ifdef STATS
    stats_init();
#endif /* STATS */
    sys_init();
    mem_init();
    memp_init();
    pbuf_init();
    print("System initialized.\n");
    
    netif_init();
    sem = sys_sem_new(0);
    tcpip_init(tcpip_init_done, &sem);
    sys_sem_wait(sem);
    sys_sem_free(sem);
    print("TCP/IP initialized.\n");
    
    IP4_ADDR(&gw, 127,0,0,1);
    IP4_ADDR(&ipaddr, 127,0,0,1);
    IP4_ADDR(&netmask, 255,0,0,0);
  
    netif_add(&ipaddr, &netmask, &gw, loopif_init,
	    tcpip_input);
	    
    IP4_ADDR(&gw, 10,0,0,1);
    IP4_ADDR(&ipaddr, 10,0,0,2);
    IP4_ADDR(&netmask, 255,0,0,0);
  
    netif_set_default(netif_add(&ipaddr, &netmask, &gw, ne2k_init,tcpip_input));
  


    print("Applications started.\n");

    tcpecho_init();
    print(" tcpecho created!");
    rtlif = rtl8019if_netif->state; //test!!!!!  

    /* Block for ever. */
    sem = sys_sem_new(0);
    sys_sem_wait(sem);
    print(" never goes here, should not appear!");

	//OSSemPend(sem,0,NULL);
	/*
	uart_sendstring("in task1\n");
	OSTimeDly(1);
	uart_sendstring("in task1 - 2\n");
	*/
#else
	uart_printf("in task%d\n",1);
	while(1) {
		c = uart_getch();
		uart_sendbyte(c);
	}
#endif

	OSTaskDel(OS_PRIO_SELF);
}

void task2(void* p) {
	char c;

	do {
		//print("in task2\n");
		OSTimeDly(10000);
	} while(1);
//	OSSemPost(sem);
	/*
	while(1) {
		c = uart_getch();
		uart_sendbyte(c);
	}
	*/
	OSTaskDel(OS_PRIO_SELF);
}

static void  tcpecho_thread(void *arg) {
  struct netconn *conn, *newconn;
  struct ip_addr deb;

  err_t err;
 /*
 void* ptr;

 ptr = mem_malloc(100);
 snprintf(ptr,100,"helloworld\n");
 PRINT("%s",ptr);
 mem_free(ptr);
 */

  /* Create a new connection identifier. */
  conn = netconn_new(NETCONN_TCP);

  /* Bind connection to well known port number 7. */
  netconn_bind(conn, NULL, 7);

  /* Tell connection to go into listening mode. */
  netconn_listen(conn);

  while(1) {

	/* Grab new connection. */
	newconn = netconn_accept(conn);
	/*printf("accepted new connection %p\n", newconn);*/
	/* Process the new connection. */
	if(newconn != NULL) {
	  struct netbuf *buf;
	  void *data;
	  u16_t len;
	  
	  while((buf = netconn_recv(newconn)) != NULL) {
	/*printf("Recved\n");*/
	do {
	  netbuf_data(buf, &data, &len);
	  err = netconn_write(newconn, data, len, NETCONN_COPY);
	  if(err != ERR_OK) {
		/*		printf("tcpecho: netconn_write: error \"%s\"\n", lwip_strerr(err));*/
	  }
	} while(netbuf_next(buf) >= 0);
	netbuf_delete(buf); 
	  }
	  /*printf("Got EOF, looping\n");*/
	  /* Close connection and discard connection identifier. */
	  netconn_delete(newconn);
	}
  }
}

void tcpecho_init(void) {
  sys_thread_new(tcpecho_thread, NULL);  
}

void tcpip_init_done(void *arg) {
  sys_sem_t *sem;
  sem = arg;
  sys_sem_signal(*sem);
}

void install_irqhandler(void * isr)                                             
{   
    /* ARM irq exception vector addr is 0x00000018  */
    unsigned int * irq_vec_addr = ( unsigned int * ) 0x18;
    /* this is isr entry address, could be another address like 0x3c, 0x58... */
    unsigned int * isr_entry_addr = ( unsigned int * ) 0x38;                    
    
    unsigned int instruction;                                                   
    
    /* set the ISR entry at 0x38  */
    *isr_entry_addr = (unsigned int)isr;                                        
    
    /* make an instruction: it is machine-code for "ldr  pc, [pc, #(38-18-8)]"  */
    instruction = ((unsigned int) isr_entry_addr  - (unsigned int)irq_vec_addr - 0x08) | 0xe59ff000;
    
    /* set this instruction at 0x18  */                                         
    *irq_vec_addr = instruction;    
}

void do_irq(void) {
	unsigned long vINTPND = 0;
	unsigned long vI_ISPR = 0;
	
#if 0
	vINTPND = rINTPND;
	vI_ISPR = rI_ISPR;
	uart_printf("in do_irq: INTPND = %x\tI_ISPR = %x\n", 
					vINTPND,vI_ISPR);
	uart_sendbyte('*');
#endif

	rI_ISPC    = BIT_TIMER0;      //clear pending_bit
	rEXTINTPND = 0xf;               //clear EXTINTPND reg.   

	OSTimeTick();
	
}
